/*
    消息具象层：对抽象层消息基类的派生，根据不同的消息，派生不同的具体类型，并实现其特有的方法
        1.请求类型：rpc请求、topic请求、service请求
        2.响应类型：rpc响应、topic响应、service响应
*/

#pragma once
#include "json.hpp"
#include "log.hpp"
#include "abstract.hpp"

namespace ns_jsonrpc
{
    // json消息抽象类
    class JsonMessage : public BaseMessage
    {
    public:
        using JsonMessagePtr = std::shared_ptr<JsonMessage>;
        virtual std::string serialize()
        {
            std::string bodyJsonStr;
            bool res = JSON::serialize(_body, bodyJsonStr);
            if (!res)
                return std::string();
            return bodyJsonStr;
        }

        virtual bool unSerialize(const std::string &bodyJsonStr)
        {
            return JSON::unSerialize(bodyJsonStr, _body);
        }

    protected:
        Json::Value _body;
    };

    // json请求抽象类
    class JsonRequest : public JsonMessage
    {
    public:
        using JsonRequestPtr = std::shared_ptr<JsonRequest>;
    };

    // rpc请求类
    class RpcRequest : public JsonRequest
    {
    public:
        using RpcRequestPtr = std::shared_ptr<RpcRequest>;
        virtual bool check() override
        {
            if (_body[KEY_METHOD].isNull() == true || _body[KEY_METHOD].isString() == false)
            {
                LOG_ERROR("method is null or not string\n");
                return false;
            }
            if (_body[KEY_PARAMS].isNull() == true || _body[KEY_PARAMS].isObject() == false)
            {
                LOG_ERROR("params is null or not object\n");
                return false;
            }
            return true;
        }

        std::string method()
        {
            return _body[KEY_METHOD].asString();
        }

        void setMethod(const std::string &method)
        {
            _body[KEY_METHOD] = method;
        }

        Json::Value params()
        {
            return _body[KEY_PARAMS];
        }

        void setParams(const Json::Value &params)
        {
            _body[KEY_PARAMS] = params;
        }
    };

    // topic请求类
    class TopicRequest : public JsonRequest
    {
    public:
        using TopicRequestPtr = std::shared_ptr<TopicRequest>;
        virtual bool check() override
        {
            if (_body[KEY_TOPIC_KEY].isNull() == true || _body[KEY_TOPIC_KEY].isString() == false)
            {
                LOG_ERROR("topic key is null or not string\n");
                return false;
            }
            if (_body[KEY_OPTYPE].isNull() == true || _body[KEY_OPTYPE].isIntegral() == false)
            {
                LOG_ERROR("topic optype is null or not integral\n");
                return false;
            }
            if (_body[KEY_OPTYPE].asInt() == (int)TopicOpType::TOPIC_PUBLISH &&
                (_body[KEY_TOPIC_MSG].isNull() == true || _body[KEY_TOPIC_MSG].isString() == false))
            {
                LOG_ERROR("topic msg is null or not string\n");
                return true;
            }
            return true;
        }

        std::string key()
        {
            return _body[KEY_TOPIC_KEY].asString();
        }

        void setKey(const std::string &key)
        {
            _body[KEY_TOPIC_KEY] = key;
        }

        TopicOpType opType()
        {
            return (TopicOpType)_body[KEY_OPTYPE].asInt();
        }

        void setOpType(TopicOpType optype)
        {
            _body[KEY_OPTYPE] = (int)optype;
        }

        std::string msg()
        {
            return _body[KEY_TOPIC_MSG].asString();
        }

        void setMsg(const std::string &msg)
        {
            _body[KEY_TOPIC_MSG] = msg;
        }
    };

    // service请求类
    typedef std::pair<std::string, int> Address;
    class ServiceRequest : public JsonRequest
    {
    public:
        using ServiceRequestPtr = std::shared_ptr<ServiceRequest>;
        virtual bool check() override
        {
            if (_body[KEY_METHOD].isNull() == true || _body[KEY_METHOD].isString() == false)
            {
                LOG_ERROR("method is null or not string\n");
                return false;
            }
            if (_body[KEY_OPTYPE].isNull() == true || _body[KEY_OPTYPE].isIntegral() == false)
            {
                LOG_ERROR("service optype is null or not integral\n");
                return false;
            }
            if (_body[KEY_OPTYPE].asInt() != (int)ServiceOpType::SERVICE_DISCOVERY &&
                (_body[KEY_HOST].isNull() == true || _body[KEY_HOST].isObject() == false ||
                 _body[KEY_HOST][KEY_HOST_IP].isNull() == true || _body[KEY_HOST][KEY_HOST_IP].isString() == false ||
                 _body[KEY_HOST][KEY_HOST_PORT].isNull() == true || _body[KEY_HOST][KEY_HOST_PORT].isIntegral() == false))
            {
                LOG_ERROR("service host is null or not integer and string\n");
                return false;
            }
            return true;
        }

        std::string method()
        {
            return _body[KEY_METHOD].asString();
        }

        void setMethod(const std::string &method)
        {
            _body[KEY_METHOD] = method;
        }

        ServiceOpType opType()
        {
            return (ServiceOpType)_body[KEY_OPTYPE].asInt();
        }

        void setOpType(ServiceOpType optype)
        {
            _body[KEY_OPTYPE] = (int)optype;
        }

        Address host()
        {
            Address addr;
            addr.first = _body[KEY_HOST][KEY_HOST_IP].asString();
            addr.second = _body[KEY_HOST][KEY_HOST_PORT].asInt();
            return addr;
        }

        void setHost(const Address &addr)
        {
            Json::Value host;
            host[KEY_HOST_IP] = addr.first;
            host[KEY_HOST_PORT] = addr.second;
            _body[KEY_HOST] = host;
        }
    };

    // json响应抽象类
    class JsonResponse : public JsonMessage
    {
    public:
        using JsonResponsePtr = std::shared_ptr<JsonResponse>;

        // rcode响应状态码是每个响应必有的字段，统一获取和设置，减少在每个派生类中实现冗余
        virtual RCode rcode()
        {
            return (RCode)_body[KEY_RCODE].asInt();
        }

        virtual void setRCode(RCode rcode)
        {
            _body[KEY_RCODE] = (int)rcode;
        }
    };

    // rpc响应类
    class RpcResponse : public JsonResponse
    {
    public:
        using RpcResponsePtr = std::shared_ptr<RpcResponse>;
        virtual bool check() override
        {
            if (_body[KEY_RCODE].isNull() == true || _body[KEY_RCODE].isIntegral() == false)
            {
                LOG_ERROR("rcode is null or not integral\n");
                return false;
            }
            if (_body[KEY_RESULT].isNull() == true)
            {
                LOG_ERROR("result is null or not object\n");
                return false;
            }
            return true;
        }

        Json::Value result()
        {
            return _body[KEY_RESULT];
        }

        void setResult(const Json::Value &result)
        {
            _body[KEY_RESULT] = result;
        }
    };

    // topic响应类
    class TopicResponse : public JsonResponse
    {
    public:
        using TopicResponsePtr = std::shared_ptr<TopicResponse>;
        virtual bool check() override
        {
            if (_body[KEY_RCODE].isNull() == true || _body[KEY_RCODE].isIntegral() == false)
            {
                LOG_ERROR("rcode is null or not integral\n");
                return false;
            }
            return true;
        }
    };

    // service响应类
    class ServiceResponse : public JsonResponse
    {
    public:
        using ServiceResponsePtr = std::shared_ptr<ServiceResponse>;
        virtual bool check() override
        {
            if (_body[KEY_RCODE].isNull() == true || _body[KEY_RCODE].isIntegral() == false)
            {
                LOG_ERROR("rcode is null or not integral\n");
                return false;
            }
            if (_body[KEY_OPTYPE].isNull() == true || _body[KEY_OPTYPE].isIntegral() == false)
            {
                LOG_ERROR("optype is null or not integral\n");
                return false;
            }
            if (_body[KEY_OPTYPE].asInt() == (int)ServiceOpType::SERVICE_DISCOVERY &&
                (_body[KEY_METHOD].isNull() == true || _body[KEY_METHOD].isString() == false ||
                 _body[KEY_HOST].isNull() == true || _body[KEY_HOST].isArray() == false))
            {
                LOG_ERROR("host is null or not array\n");
                return false;
            }
            return true;
        }

        ServiceOpType optype()
        {
            return (ServiceOpType)_body[KEY_OPTYPE].asInt();
        }

        void setOptype(ServiceOpType optype)
        {
            _body[KEY_OPTYPE] = (int)optype;
        }

        std::vector<Address> hosts()
        {
            std::vector<Address> addrs;
            int sz = _body[KEY_HOST].size();
            for (int i = 0; i < sz; i++)
            {
                Address addr;
                addr.first = _body[KEY_HOST][i][KEY_HOST_IP].asString();
                addr.second = _body[KEY_HOST][i][KEY_HOST_PORT].asInt();
                addrs.push_back(addr);
            }
            return addrs;
        }

        void setHosts(const std::vector<Address> &addrs)
        {
            for (auto &addr : addrs)
            {
                Json::Value host;
                host[KEY_HOST_IP] = addr.first;
                host[KEY_HOST_PORT] = addr.second;
                _body[KEY_HOST].append(host);
            }
        }

        void setMethod(const std::string &method)
        {
            _body[KEY_METHOD] = method;
        }

        std::string method()
        {
            return _body[KEY_METHOD].asString();
        }
    };

    // 生产消息的工厂类
    class MessageFactory
    {
    public:
        // 根据消息类型生产消息
        static BaseMessage::BaseMessagePtr create(MType mtype)
        {
            switch (mtype)
            {
            case MType::REQ_RPC:
                return std::make_shared<RpcRequest>();
            case MType::RSP_RPC:
                return std::make_shared<RpcResponse>();
            case MType::REQ_TOPIC:
                return std::make_shared<TopicRequest>();
            case MType::RSP_TOPIC:
                return std::make_shared<TopicResponse>();
            case MType::REQ_SERVICE:
                return std::make_shared<ServiceRequest>();
            case MType::RSP_SERVICE:
                return std::make_shared<ServiceResponse>();
            default:
                return BaseMessage::BaseMessagePtr();
            }
        }

        // 模板静态函数，创建任意类型的智能指针（构造智能指针时，支持传任意个数和类型的形参）
        template <typename T, typename... Args>
        static std::shared_ptr<T> create(Args &&...args)
        {
            return std::make_shared<T>(std::forward<Args>(args)...);
        }
    };
}